package com.logger.service;

import java.io.BufferedReader;
import java.io.CharArrayReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;
import java.util.Set;
import java.util.TreeSet;

public class HtmlCreator
{
	private static HtmlCreator	instance;

	public synchronized static HtmlCreator getInstance()
	{
		if (instance == null)
		{
			instance = new HtmlCreator();
		}
		return instance;
	}

	private HtmlCreator()
	{

	}

	public boolean createHtml(String logBytes, Writer writer)
	{
		if (writer == null || logBytes == null)
			return false;
		BufferedReader reader = new BufferedReader(new CharArrayReader(logBytes.toCharArray()));
		Set<String> tags = new TreeSet<String>();
		Set<Integer> pids = new TreeSet<Integer>();
		try
		{
			writeHead(writer);
			int lineNum = 0;
			while (reader.ready())
			{
				String line = reader.readLine();
				lineNum++;
				// System.out.println(line);
				LogBean log = parseLine(line, lineNum);
				if (log == null)
					continue;// 跳过错误行
				pids.add(log.pid);
				tags.add(log.tag);
				writeBody(writer, log);
			}
			writeEnd(writer, pids, tags);
		}
		catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally
		{
		}

		return true;
	}

	public boolean createHtml(File logFile, File htmlFile)
	{
		if (logFile == null || htmlFile == null)
			throw new NullPointerException("argument is null.");

		Writer writer = null;
		BufferedReader reader = null;
		try
		{
			reader = new BufferedReader(new InputStreamReader(new FileInputStream(logFile), "GBK"));
			// writer = new BufferedWriter(new OutputStreamWriter(new
			// FileOutputStream(htmlFile),
			// "utf-8"));

			Set<String> tags = new TreeSet<String>();
			Set<Integer> pids = new TreeSet<Integer>();
			writeHead(writer);
			int lineNum = 0;
			while (reader.ready())
			{
				String line = reader.readLine();
				lineNum++;
				// System.out.println(line);
				LogBean log = parseLine(line, lineNum);
				if (log == null)
					continue;// 跳过错误行
				pids.add(log.pid);
				tags.add(log.tag);
				writeBody(writer, log);
			}
			writeEnd(writer, pids, tags);

			return true;
		}
		catch (IOException e)
		{
			e.printStackTrace();
			return false;
		}
		finally
		{
			if (writer != null)
			{
				try
				{
					writer.flush();
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}
				try
				{
					writer.close();
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}
			}
			if (reader != null)
			{
				try
				{
					reader.close();
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}
			}
		}
	}

	private void writeHead(Writer writer) throws IOException
	{
		writer.write("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/></head>"
				+ "<body onload='init();'>"
				+ "<table id=tab_ID border=1 cellspacing='5' bordercolor='EEEEEE' style='font-size:10pt'>"
				+ "<tr style='font-size:12pt;background-color:EEEEEE;border-color:D5D5D5'>"
				+ "<td><select onchange='filter();' id=LSel_ID>"
				+ "<option value=''>Level</option>"
				+ "<option value='E'>E</option>"
				+ "<option value='W'>W</option>"
				+ "<option value='I'>I</option>"
				+ "<option value='D'>D</option>"
				+ "<option value='V'>V</option>"
				+ "</select></td>"
				+ "<td>Time</td>"
				+ "<td id='pidTD'><select onchange='filter();' id=PSel_ID><option value=''>PID</option></select></td>"
				+ "<td id='tagTD'><select onchange='filter();' id=TSel_ID><option value=''>Tag(All)</option></select></td>"
				+ "<td>Text</td>" + "</tr>");
	}

	private void writeBody(Writer writer, LogBean log) throws IOException
	{
		writer.write("<tr style='color:");
		writer.write(log.getColor());
		writer.write("'><td>");
		writer.write(String.valueOf(log.logType));
		writer.write("</td><td noWrap>");
		writer.write(log.time);
		writer.write("</td><td>");
		writer.write(String.valueOf(log.pid));
		writer.write("</td><td>");
		writer.write(log.tag);
		writer.write("</td><td>");
		writer.write(log.text);
		writer.write("</td></tr>");
	}

	private void writeEnd(Writer writer, Set<Integer> pids, Set<String> tags) throws IOException
	{
		StringBuilder sb = new StringBuilder();
		boolean firstEle = true;
		for (int pid : pids)
		{
			if (!firstEle)
			{
				sb.append(",");
			}
			sb.append("\"");
			sb.append(String.valueOf(pid));
			sb.append("\"");
			firstEle = false;
		}
		String pidStr = sb.toString();

		sb = new StringBuilder();
		firstEle = true;
		for (String tag : tags)
		{
			if (!firstEle)
			{
				sb.append(",");
			}
			sb.append("\"");
			sb.append(tag);
			sb.append("\"");
			firstEle = false;
		}
		String tagStr = sb.toString();
		writer.write("</table>"
				+ "<script type=\"text/javascript\">"
				+ "function filter() {"
				+ "	filterShow(document.getElementById('LSel_ID').value,document.getElementById('PSel_ID').value,document.getElementById('TSel_ID').value);"
				+ "}"
				+ "function filterShow(level,pid,tag) {"
				+ "	var L=0,P=2,T=3;var tabEle = document.getElementById('tab_ID');"
				+ "	for (i=1; i < tabEle.rows.length; i++) {"
				+ "		var show=false;"
				+ "		if(level==\"\"&&pid==\"\"&&tag==\"\")"
				+ "			show=true;"
				+ "		else if((level==\"\"||tabEle.rows[i].cells[L].innerHTML==level)&&(pid==\"\"||tabEle.rows[i].cells[P].innerHTML==pid)&&(tag==\"\"||tabEle.rows[i].cells[T].innerHTML==tag))"
				+ "			show=true;" + "		tabEle.rows[i].style.display=show?\"\":\"none\";" + "	}"
				+ "}" + "function init(){" + "	var pids=new Array(");

		writer.write(pidStr);
		writer.write(");" + "	var tags=new Array(");
		writer.write(tagStr);
		writer.write(");"
				+ "var pidTD=document.getElementById('pidTD');"
				+ "var tagTD=document.getElementById('tagTD');"
				+ "var tmpStr=\"\";"
				+ "for(i=0;i<pids.length;i++)"
				+ "	tmpStr+=\"<option value='\"+pids[i]+\"'>\"+pids[i]+\"</option>\";"
				+ "pidTD.innerHTML=\"<select onchange='filter();' id=PSel_ID><option value=''>PID</option>\"+tmpStr+\"</select>\";"
				+ "tmpStr=\"\";"
				+ "for(i=0;i<tags.length;i++)"
				+ "	tmpStr+=\"<option value='\"+tags[i]+\"'>\"+tags[i]+\"</option>\";"
				+ "tagTD.innerHTML=\"<select onchange='filter();' id=TSel_ID><option value=''>Tag(All)</option>\"+tmpStr+\"</select>\";"
				+ "}</script></body></html>");
	}

	private LogBean parseLine(String logLine, int lineNum)
	{
		if (logLine == null)
			return null;

		int length = logLine.length();
		LogBean log = new LogBean();

		// parse time:
		int end = logLine.indexOf('/');
		if (end < 0)
		{
			System.err.println("Line." + lineNum + " Parse Time Error! Error String: " + logLine);
			return null;
		}
		int begin = logLine.lastIndexOf(' ', end);
		if (begin < 0)
		{
			System.err.println("Line." + lineNum + " Parse Time Error! Error String: " + logLine);
			return null;
		}
		log.time = logLine.substring(0, begin).trim();

		// parse type:
		if (++begin >= length)
		{
			System.err.println("Line." + lineNum + " Parse Type Error! Error String: " + logLine);
			return null;
		}
		log.logType = parseType(logLine.charAt(begin));
		if (log.logType == null)
		{
			System.err.println("Line." + lineNum + " Unkown logType! Error String: " + logLine);
			return null;
		}

		// parse tag:
		begin = ++end;
		int index = logLine.indexOf(':', begin);
		if (begin >= length || index < 0)
		{
			System.err.println("Line." + lineNum + " Parse Tag Error! Error String: " + logLine);
			return null;
		}
		end = logLine.lastIndexOf('(', index);
		if (end < 0)
		{
			System.err.println("Line." + lineNum + " Parse Tag Error! Error String: " + logLine);
			return null;
		}
		log.tag = logLine.substring(begin, end).trim();

		// parse pid:
		begin = end + 1;
		end = logLine.lastIndexOf(')', index);
		if (begin >= length || end < 0)
		{
			System.err.println("Line." + lineNum + " Parse Pid Error! Error String: " + logLine);
			return null;
		}
		try
		{
			log.pid = Integer.parseInt(logLine.substring(begin, end).trim());
		}
		catch (NumberFormatException e)
		{
			System.err.println("Line." + lineNum
					+ ", parse pid NumberFormatException! Error String: " + logLine);
			e.printStackTrace();
			return null;
		}

		// parse text:
		if (++index >= length)
		{
			System.err.println("Line." + lineNum + " Parse Text Error! Error String: " + logLine);
			return null;
		}
		log.text = encode4Html(logLine.substring(index));

		// String[] tmp = logLine.split(" ", 4);
		// if (tmp == null || tmp.length != 4) {
		// // throw new IllegalArgumentException("Error String: " + logLine);
		// System.err.println("Line." + lineNum + " Error String: " + logLine);
		// return null;
		// }
		//
		// try {
		// log.time = tmp[1].substring(0, tmp[1].length() - 1);
		// } catch (IndexOutOfBoundsException e) {
		// System.err
		// .println("Line." + lineNum + " IndexOutOfBoundsException");
		// e.printStackTrace();
		// return null;
		// }
		// log.time = tmp[0].concat("&nbsp;").concat(log.time);
		//
		//
		// log.logType = parseType(tmp[2].charAt(0));
		// if (log.logType == null) {
		// System.err.println("Line." + lineNum + " Unkown logType : "
		// + tmp[2].charAt(0));
		// return null;
		// }
		//
		// int index = tmp[2].indexOf('/') + 1;
		// int end = tmp[2].lastIndexOf('(');
		// try {
		// log.tag = tmp[2].substring(index, end);
		// } catch (IndexOutOfBoundsException e) {
		// System.err
		// .println("Line." + lineNum + " IndexOutOfBoundsException");
		// e.printStackTrace();
		// return null;
		// }
		// index = ++end;
		// end = tmp[2].indexOf(')', index);
		// try {
		// log.pid = Integer.parseInt(tmp[2].substring(index, end).trim());
		// } catch (IndexOutOfBoundsException e) {
		// System.err
		// .println("Line." + lineNum + " IndexOutOfBoundsException");
		// e.printStackTrace();
		// return null;
		// } catch (NumberFormatException e) {
		// System.err.println("Line." + lineNum + " NumberFormatException");
		// e.printStackTrace();
		// return null;
		// }
		// log.text = encode4Html(tmp[3]);//
		// StringEscapeUtils.escapeHtml4(tmp[3]);
		return log;
	}

	private LogType parseType(char ch)
	{
		switch (ch)
		{
			case 'W':
				return LogType.W;
			case 'E':
				return LogType.E;
			case 'I':
				return LogType.I;
			case 'D':
				return LogType.D;
			case 'V':
				return LogType.V;
		}
		return null;
	}

	public enum LogType
	{
		W, E, I, D, V
	};

	class LogBean
	{
		LogType	logType;
		String	time;
		int		pid;
		String	tag;
		String	text;

		String getColor()
		{
			switch (logType)
			{
				case W:
					return "CE9F30";
				case E:
					return "FE2222";
				case I:
					return "0A981C";
				case D:
					return "2522AE";
				case V:
				default:
					return "222222";
			}
		}
	}

	/**
	 * 转换为html字符
	 */
	public static String encode4Html(String value)
	{
		if (value == null || value.trim().equals(""))
			return "";
		StringBuffer result = new StringBuffer();
		for (int i = 0; i < value.length(); i++)
		{
			char ch = value.charAt(i);
			if (ch == '<')
				result.append("&lt;");
			else if (ch == '&')
				result.append("&amp;");
			else if (ch == '"')
				result.append("&quot;");
			else if (ch == '\r')
				result.append("<BR>");
			else if (ch == '\n')
			{
				if (value.charAt(i - 1) == '\r')
				{
				}
				else
					result.append("<BR>");
			}
			else if (ch == '\t')
				result.append("&emsp;");
			else if (ch == ' ')
				result.append("&nbsp;");
			else
				result.append(ch);
		}
		return result.toString();
	}
}
